package com.hyf.gateway.zuul;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.cloud.netflix.zuul.filters.RefreshableRouteLocator;
import org.springframework.cloud.netflix.zuul.filters.SimpleRouteLocator;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 定制的路由，
 */
public class CustomRouteLocator extends SimpleRouteLocator implements RefreshableRouteLocator {

    private final static Logger logger=LoggerFactory.getLogger(CustomRouteLocator.class);

    private JdbcTemplate jdbcTemplate;
    private ZuulProperties properties;

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public CustomRouteLocator(String servletPath, ZuulProperties properties) {
        super(servletPath, properties);
        this.properties=properties;
        logger.info("serverPath:{}",servletPath);
    }

    //父类SimpleRouteLocator提供了这个方法，写出来说明这个方法很重要！！！
    @Override
    protected void doRefresh() {
        super.doRefresh();
    }

    @Override
    public void refresh() {
        doRefresh();
    }


    @Override
    protected Map<String, ZuulProperties.ZuulRoute> locateRoutes() {
        LinkedHashMap<String, ZuulProperties.ZuulRoute> routesMap = new LinkedHashMap<String, ZuulProperties.ZuulRoute>();
        //从application.properties 加载路由信息
        routesMap.putAll(super.locateRoutes());

        //从db加载路由信息,自己实现的
        routesMap.putAll(locateRoutesFromDB());
        //优化一下配置
        LinkedHashMap<String, ZuulProperties.ZuulRoute> values = new LinkedHashMap<String, ZuulProperties.ZuulRoute>();
        for (Map.Entry<String, ZuulProperties.ZuulRoute> entry : routesMap.entrySet()) {
            String path = entry.getKey();
            if(!path.startsWith("/")){
                path="/"+path;
            }
            if(org.springframework.util.StringUtils.hasText(this.properties.getPrefix())){
                path=this.properties.getPrefix()+path;
                if(!path.startsWith("/")){
                    path="/"+path;
                }
            }
            values.put(path,entry.getValue());
        }

        return values;
    }

    protected Map<String, ZuulProperties.ZuulRoute> locateRoutesFromDB(){
        LinkedHashMap<String, ZuulProperties.ZuulRoute> routesMap = new LinkedHashMap<String, ZuulProperties.ZuulRoute>();
        String sql="select * from gateway_api_define where enabled = true";
        List<ZuulRouteVO> results = jdbcTemplate.query(sql, new BeanPropertyRowMapper(ZuulRouteVO.class));
        for(ZuulRouteVO result:results){
            if(StringUtils.isBlank(result.getPath()) || StringUtils.isBlank(result.getUrl())){
                continue;
            }
            ZuulProperties.ZuulRoute zuulRoute=new ZuulProperties.ZuulRoute();
            try {
                BeanUtils.copyProperties(result,zuulRoute);
            }catch (Exception e){
                logger.error("====load zuul route info from db with error===",e);
            }
            routesMap.put(zuulRoute.getPath(),zuulRoute);
        }
        return routesMap;
    }

    /**
     * 参照ZuulRoute类的成员变量
     */
    public static class ZuulRouteVO{

        /**
         * The ID of the route (the same as its map key by default).
         */
        private String id;

        /**
         * The path (pattern) for the route, e.g. /foo/**.
         */
        private String path;

        /**
         * The service ID (if any) to map to this route. You can specify a physical URL or
         * a service, but not both.
         */
        private String serviceId;

        /**
         * A full physical URL to map to the route. An alternative is to use a service ID
         * and service discovery to find the physical address.
         */
        private String url;

        /**
         * Flag to determine whether the prefix for this route (the path, minus pattern
         * patcher) should be stripped before forwarding.
         */
        private boolean stripPrefix = true;

        /**
         * Flag to indicate that this route should be retryable (if supported). Generally
         * retry requires a service ID and ribbon.
         */
        private Boolean retryable;


        private String apiName;
        //是否激活
        private Boolean enabled;


        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getPath() {
            return path;
        }

        public void setPath(String path) {
            this.path = path;
        }

        public String getServiceId() {
            return serviceId;
        }

        public void setServiceId(String serviceId) {
            this.serviceId = serviceId;
        }

        public String getUrl() {
            return url;
        }

        public void setUrl(String url) {
            this.url = url;
        }

        public boolean isStripPrefix() {
            return stripPrefix;
        }

        public void setStripPrefix(boolean stripPrefix) {
            this.stripPrefix = stripPrefix;
        }

        public Boolean getRetryable() {
            return retryable;
        }

        public void setRetryable(Boolean retryable) {
            this.retryable = retryable;
        }

        public String getApiName() {
            return apiName;
        }

        public void setApiName(String apiName) {
            this.apiName = apiName;
        }

        public Boolean getEnabled() {
            return enabled;
        }

        public void setEnabled(Boolean enabled) {
            this.enabled = enabled;
        }
    }
}
